using System;
using System.Collections.Generic;
using System.Security.Principal;

namespace InfiniTec.DirectoryServices
{
    /// <summary>
    /// This class extends the <see cref="ActiveDirectoryPrincipal"/> class with 
    /// properties available on ActiveDirectory groups.
    /// </summary>
    public class ActiveDirectoryGroup: ActiveDirectoryPrincipal
    {
        private const int SecurityGroupFlag = -2147483648;
        private const int GroupMask = 0xff;

        /// <summary>
        /// Initializes a new instance of the <see cref="ActiveDirectoryGroup"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="hint">The hint.</param>
        /// <param name="connection">The connection.</param>
        public ActiveDirectoryGroup(string name, NameHint hint, Connection connection) : base(name, hint, connection)
        {
            AddRequiredFields(SchemaMapping.GroupSchema);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActiveDirectoryGroup"/> class.
        /// </summary>
        /// <param name="identifier">The identifier.</param>
        /// <param name="connection">The connection.</param>
        public ActiveDirectoryGroup(SecurityIdentifier identifier, Connection connection) : base(identifier, connection)
        {
            AddRequiredFields(SchemaMapping.GroupSchema);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActiveDirectoryGroup"/> class.
        /// </summary>
        /// <param name="name">The name of the element. This can be a distinguished name, nt4 account name, email address, legacy exchange distinguished name or a display name. In the latter case, Ambiguous name resolution is used to find the principal.</param>
        /// <param name="connection">The connection.</param>
        /// <remarks>
        /// This constructor is equivalent to the constructor <see cref="ActiveDirectoryPrincipal(string, NameHint, Connection)"/>.
        /// </remarks>
        public ActiveDirectoryGroup(string name, Connection connection) : base(name, connection)
        {
            AddRequiredFields(SchemaMapping.GroupSchema);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActiveDirectoryGroup"/> class.
        /// </summary>
        /// <param name="objectId">The object id.</param>
        /// <param name="connection">The connection.</param>
        public ActiveDirectoryGroup(Guid objectId, Connection connection) : base(objectId, connection)
        {
            AddRequiredFields(SchemaMapping.GroupSchema);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActiveDirectoryGroup"/> class.
        /// </summary>
        /// <param name="baseItem">The base item.</param>
        public ActiveDirectoryGroup(Item baseItem) : base(baseItem)
        {
            AddRequiredFields(SchemaMapping.GroupSchema);
        }

        /// <summary>
        /// Gets the members of the group.
        /// </summary>
        /// <value>The members of the group.</value>
        public IList<string> Members
        {
            get
            {
                return Properties.GetMultiValuedPropertyValue(WellknownProperties.Group.Member);
            }
        }

        /// <summary>
        /// Gets the group scope.
        /// </summary>
        /// <value>The group scope.</value>
        public GroupScope? Scope
        {
            get
            {
                GroupType? result;

                result = Properties.GetPropertyValue(WellknownProperties.Group.GroupType);
                return (result != null) ? (GroupScope?)(result & (GroupType?) GroupMask) : null;
            }
        }

        /// <summary>
        /// Gets types of principals to resolve by this instance.
        /// </summary>
        /// <returns></returns>
        protected override ResolveTypes GetResolveTypes()
        {
            return ResolveTypes.User;
        }


        /// <summary>
        /// Gets the type of the group.
        /// </summary>
        /// <value>The type of the group.</value>
        public GroupType? Type
        {
            get
            {
                var result = Properties.GetPropertyValue(WellknownProperties.Group.GroupType);
                return (result != null) ? (GroupType?) (result.Value & (GroupType) SecurityGroupFlag) : null;
            }
        }
    }
}
